from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import timezone
from datetime import date, timedelta
import secrets
import string

class UserProfile(models.Model):
    """用户个人信息模型"""
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    bio = models.TextField(max_length=500, blank=True, verbose_name='个人简介')
    location = models.CharField(max_length=30, blank=True, verbose_name='所在地')
    birth_date = models.DateField(null=True, blank=True, verbose_name='出生日期')
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True, verbose_name='头像')
    
    # 经验值系统字段
    level = models.IntegerField(default=1, verbose_name='等级')
    exp = models.IntegerField(default=0, verbose_name='当前经验值')
    total_exp = models.IntegerField(default=0, verbose_name='总经验值')
    
    # 成就系统
    title = models.CharField(max_length=50, blank=True, verbose_name='称号')
    
    def __str__(self):
        return f'{self.user.username}的个人资料'
    
    @property
    def next_level_exp(self):
        """计算升级所需经验值"""
        return self.calculate_level_exp(self.level + 1)
    
    @property
    def exp_percentage(self):
        """计算经验值百分比"""
        current_level_exp = self.calculate_level_exp(self.level)
        next_level_exp = self.calculate_level_exp(self.level + 1)
        level_exp_range = next_level_exp - current_level_exp
        current_progress = self.total_exp - current_level_exp
        return min(100, (current_progress / level_exp_range) * 100) if level_exp_range > 0 else 0
    
    @staticmethod
    def calculate_level_exp(level):
        """计算指定等级所需的总经验值"""
        if level <= 1:
            return 0
        # 经验值公式：基础经验 * (等级^1.5) + 额外经验
        base_exp = 100
        return int(base_exp * (level ** 1.5) + (level - 1) * 50)
    
    def add_exp(self, amount, reason=""):
        """增加经验值并处理升级"""
        old_level = self.level
        self.exp += amount
        self.total_exp += amount
        
        # 检查是否升级
        while self.total_exp >= self.calculate_level_exp(self.level + 1):
            self.level += 1
        
        self.save()
        
        # 记录经验值获得日志
        ExpLog.objects.create(
            user=self.user,
            amount=amount,
            reason=reason,
            level_before=old_level,
            level_after=self.level
        )
        
        # 如果升级了，触发升级奖励
        if self.level > old_level:
            self.handle_level_up(old_level, self.level)
        
        return self.level > old_level  # 返回是否升级
    
    def handle_level_up(self, old_level, new_level):
        """处理升级奖励和通知"""
        # 升级奖励逻辑
        bonus_exp = new_level * 10
        # 这里可以添加其他奖励逻辑
        pass


class ExpLog(models.Model):
    """经验值获得日志"""
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='exp_logs')
    amount = models.IntegerField(verbose_name='经验值数量')
    reason = models.CharField(max_length=100, verbose_name='获得原因')
    level_before = models.IntegerField(verbose_name='获得前等级')
    level_after = models.IntegerField(verbose_name='获得后等级')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='获得时间')
    
    class Meta:
        ordering = ['-created_at']
        verbose_name = '经验值日志'
        verbose_name_plural = '经验值日志'
    
    def __str__(self):
        return f'{self.user.username} +{self.amount}经验值 ({self.reason})'


class Task(models.Model):
    """任务模型"""
    TASK_TYPE_CHOICES = [
        ('daily', '每日任务'),
        ('weekly', '每周任务'),
        ('achievement', '成就任务'),
        ('special', '特殊任务'),
    ]
    
    title = models.CharField(max_length=100, verbose_name='任务标题')
    description = models.TextField(verbose_name='任务描述')
    task_type = models.CharField(max_length=20, choices=TASK_TYPE_CHOICES, verbose_name='任务类型')
    target_count = models.IntegerField(default=1, verbose_name='目标数量')
    exp_reward = models.IntegerField(default=0, verbose_name='经验值奖励')
    is_active = models.BooleanField(default=True, verbose_name='是否激活')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '任务'
        verbose_name_plural = '任务'
    
    def __str__(self):
        return self.title


class UserTask(models.Model):
    """用户任务进度模型"""
    STATUS_CHOICES = [
        ('in_progress', '进行中'),
        ('completed', '已完成'),
        ('claimed', '已领取'),
    ]
    
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_tasks')
    task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='user_tasks')
    current_count = models.IntegerField(default=0, verbose_name='当前进度')
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='in_progress', verbose_name='状态')
    started_at = models.DateTimeField(auto_now_add=True, verbose_name='开始时间')
    completed_at = models.DateTimeField(null=True, blank=True, verbose_name='完成时间')
    claimed_at = models.DateTimeField(null=True, blank=True, verbose_name='领取时间')
    
    class Meta:
        unique_together = ['user', 'task']
        verbose_name = '用户任务'
        verbose_name_plural = '用户任务'
    
    def __str__(self):
        return f'{self.user.username} - {self.task.title}'
    
    @property
    def progress_percentage(self):
        """计算任务完成百分比"""
        return min(100, (self.current_count / self.task.target_count) * 100) if self.task.target_count > 0 else 0
    
    def update_progress(self, increment=1):
        """更新任务进度"""
        if self.status != 'in_progress':
            return False
        
        self.current_count += increment
        
        # 检查是否完成任务
        if self.current_count >= self.task.target_count:
            self.status = 'completed'
            self.completed_at = timezone.now()
        
        self.save()
        return True
    
    def claim_reward(self):
        """领取任务奖励"""
        if self.status != 'completed':
            return False
        
        # 给用户增加经验值
        self.user.profile.add_exp(self.task.exp_reward, f'完成任务: {self.task.title}')
        
        self.status = 'claimed'
        self.claimed_at = timezone.now()
        self.save()
        
        return True


class Achievement(models.Model):
    """成就模型"""
    ACHIEVEMENT_TYPE_CHOICES = [
        ('battle', '战斗成就'),
        ('code', '代码成就'),
        ('social', '社交成就'),
        ('special', '特殊成就'),
    ]
    
    title = models.CharField(max_length=100, verbose_name='成就标题')
    description = models.TextField(verbose_name='成就描述')
    achievement_type = models.CharField(max_length=20, choices=ACHIEVEMENT_TYPE_CHOICES, verbose_name='成就类型')
    condition_key = models.CharField(max_length=50, verbose_name='条件键', help_text='用于程序判断的条件标识')
    condition_value = models.IntegerField(verbose_name='条件值', help_text='达成条件的数值')
    exp_reward = models.IntegerField(default=0, verbose_name='经验值奖励')
    icon = models.CharField(max_length=100, blank=True, verbose_name='图标')
    is_hidden = models.BooleanField(default=False, verbose_name='是否隐藏', help_text='隐藏成就在未达成前不显示')
    is_active = models.BooleanField(default=True, verbose_name='是否激活')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '成就'
        verbose_name_plural = '成就'
    
    def __str__(self):
        return self.title


class UserAchievement(models.Model):
    """用户成就模型"""
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_achievements')
    achievement = models.ForeignKey(Achievement, on_delete=models.CASCADE, related_name='user_achievements')
    achieved_at = models.DateTimeField(auto_now_add=True, verbose_name='达成时间')
    
    class Meta:
        unique_together = ['user', 'achievement']
        verbose_name = '用户成就'
        verbose_name_plural = '用户成就'
    
    def __str__(self):
        return f'{self.user.username} - {self.achievement.title}'


class Title(models.Model):
    """称号模型"""
    name = models.CharField(max_length=50, unique=True, verbose_name='称号名称')
    description = models.TextField(verbose_name='称号描述')
    condition_level = models.IntegerField(null=True, blank=True, verbose_name='等级条件')
    condition_achievement = models.ForeignKey(Achievement, null=True, blank=True, on_delete=models.CASCADE, verbose_name='成就条件', related_name='required_for_titles')
    color = models.CharField(max_length=7, default='#000000', verbose_name='称号颜色', help_text='十六进制颜色代码')
    is_active = models.BooleanField(default=True, verbose_name='是否激活')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '称号'
        verbose_name_plural = '称号'
    
    def __str__(self):
        return self.name
    
    def is_available_for_user(self, user):
        """检查用户是否满足称号条件"""
        # 检查等级条件
        if self.condition_level and user.profile.level < self.condition_level:
            return False
        
        # 检查成就条件
        if self.condition_achievement:
            if not user.user_achievements.filter(achievement=self.condition_achievement).exists():
                return False
        
        return True


class CheckIn(models.Model):
    """签到记录模型"""
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='checkins', verbose_name='用户')
    date = models.DateField(verbose_name='签到日期')
    consecutive_days = models.IntegerField(default=1, verbose_name='连续签到天数')
    exp_reward = models.IntegerField(default=10, verbose_name='经验值奖励')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='签到时间')
    
    class Meta:
        verbose_name = '签到记录'
        verbose_name_plural = '签到记录'
        unique_together = ('user', 'date')
        ordering = ['-date']
    
    def __str__(self):
        return f"{self.user.username} - {self.date}"
    
    @classmethod
    def check_in_today(cls, user):
        """用户今日签到"""
        today = date.today()
        
        # 检查今天是否已经签到
        if cls.objects.filter(user=user, date=today).exists():
            return None, "今天已经签到过了"
        
        # 获取昨天的签到记录
        yesterday = date.today().replace(day=date.today().day - 1) if date.today().day > 1 else None
        yesterday_checkin = None
        if yesterday:
            yesterday_checkin = cls.objects.filter(user=user, date=yesterday).first()
        
        # 计算连续签到天数
        consecutive_days = 1
        if yesterday_checkin:
            consecutive_days = yesterday_checkin.consecutive_days + 1
        
        # 计算经验值奖励（连续签到有额外奖励）
        base_exp = 10
        bonus_exp = min(consecutive_days - 1, 6) * 5  # 最多额外30经验
        total_exp = base_exp + bonus_exp
        
        # 创建签到记录
        checkin = cls.objects.create(
            user=user,
            date=today,
            consecutive_days=consecutive_days,
            exp_reward=total_exp
        )
        
        # 给用户添加经验值
        user.profile.add_exp(total_exp, f"签到奖励（连续{consecutive_days}天）")
        
        return checkin, "签到成功"
    
    @classmethod
    def get_user_checkin_status(cls, user):
        """获取用户签到状态"""
        today = date.today()
        today_checkin = cls.objects.filter(user=user, date=today).first()
        
        # 获取连续签到天数
        consecutive_days = 0
        if today_checkin:
            consecutive_days = today_checkin.consecutive_days
        else:
            # 如果今天没签到，检查昨天
            yesterday = date.today().replace(day=date.today().day - 1) if date.today().day > 1 else None
            if yesterday:
                yesterday_checkin = cls.objects.filter(user=user, date=yesterday).first()
                if yesterday_checkin:
                    consecutive_days = yesterday_checkin.consecutive_days
        
        return {
            'checked_in_today': bool(today_checkin),
            'consecutive_days': consecutive_days,
            'next_reward': 10 + min(consecutive_days, 6) * 5
        }


class UserMessage(models.Model):
    """用户留言模型"""
    from_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_messages', verbose_name='发送者')
    to_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='received_messages', verbose_name='接收者')
    content = models.TextField(max_length=500, verbose_name='留言内容')
    is_read = models.BooleanField(default=False, verbose_name='是否已读')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='留言时间')
    
    class Meta:
        verbose_name = '用户留言'
        verbose_name_plural = '用户留言'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.from_user.username} -> {self.to_user.username}: {self.content[:50]}"


# 信号接收器，在创建用户时自动创建对应的个人资料
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()


class TemporaryPassword(models.Model):
    """临时密码模型"""
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='temp_passwords', verbose_name='用户')
    temp_password = models.CharField(max_length=20, verbose_name='临时密码')
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='created_temp_passwords', verbose_name='创建者')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    expires_at = models.DateTimeField(verbose_name='过期时间')
    is_used = models.BooleanField(default=False, verbose_name='是否已使用')
    used_at = models.DateTimeField(null=True, blank=True, verbose_name='使用时间')
    
    class Meta:
        verbose_name = '临时密码'
        verbose_name_plural = '临时密码'
        ordering = ['-created_at']
    
    def __str__(self):
        return f'{self.user.username} - {self.temp_password}'
    
    @classmethod
    def generate_temp_password(cls, user, created_by, hours=24):
        """生成临时密码"""
        # 生成8位随机密码，包含字母和数字
        alphabet = string.ascii_letters + string.digits
        temp_password = ''.join(secrets.choice(alphabet) for _ in range(8))
        
        # 设置过期时间
        expires_at = timezone.now() + timedelta(hours=hours)
        
        # 创建临时密码记录
        temp_pwd = cls.objects.create(
            user=user,
            temp_password=temp_password,
            created_by=created_by,
            expires_at=expires_at
        )
        
        # 设置用户密码为临时密码
        user.set_password(temp_password)
        user.save()
        
        return temp_pwd
    
    def is_valid(self):
        """检查临时密码是否有效"""
        return not self.is_used and timezone.now() < self.expires_at
    
    def mark_as_used(self):
        """标记临时密码为已使用"""
        self.is_used = True
        self.used_at = timezone.now()
        self.save()


class FeatureSwitch(models.Model):
    """功能开关管理模型"""
    SWITCH_CHOICES = [
        ('code_operations', '代码操作'),
        ('battle_creation', '对战创建'),
        ('user_registration', '用户注册'),
        ('api_access', 'API访问'),
        ('private_code_challenge', '私有代码挑战'),
        ('login_registration_control', '禁止登录注册'),
    ]
    
    switch_key = models.CharField(max_length=50, choices=SWITCH_CHOICES, unique=True, verbose_name='功能开关')
    is_enabled = models.BooleanField(default=True, verbose_name='是否启用')
    disabled_message = models.TextField(
        max_length=200, 
        blank=True, 
        verbose_name='关闭提示信息',
        help_text='功能关闭时显示给用户的提示信息'
    )
    updated_by = models.ForeignKey(
        User, 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        verbose_name='最后更新者'
    )
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '功能开关'
        verbose_name_plural = '功能开关'
        ordering = ['switch_key']
    
    def __str__(self):
        status = "启用" if self.is_enabled else "关闭"
        return f'{self.get_switch_key_display()} - {status}'
    
    @classmethod
    def is_feature_enabled(cls, switch_key):
        """检查功能是否启用"""
        try:
            switch = cls.objects.get(switch_key=switch_key)
            return switch.is_enabled
        except cls.DoesNotExist:
            # 如果开关不存在，默认启用
            return True
    
    @classmethod
    def get_disabled_message(cls, switch_key):
        """获取功能关闭时的提示信息"""
        try:
            switch = cls.objects.get(switch_key=switch_key)
            return switch.disabled_message or '该功能已被管理员暂时关闭。'
        except cls.DoesNotExist:
            return '该功能已被管理员暂时关闭。'
